/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.bff.slimserver.musicjukebox.ui.components.favorites;

import com.bff.slimserver.music.exceptions.PlaylistException;
import com.bff.slimserver.musicjukebox.lib.JukeboxProperties;
import com.bff.slimserver.musicjukebox.ui.SplashScreen;
import com.bff.bjj.utils.Utils;
import java.awt.Component;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JTree;
import javax.swing.event.TreeExpansionEvent;
import javax.swing.event.TreeExpansionListener;
import javax.swing.event.TreeWillExpandListener;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.ExpandVetoException;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
import javax.swing.tree.TreeSelectionModel;
import org.bff.slimserver.SlimFavoritePlugin;
import org.bff.slimserver.SlimPlaylist;
import org.bff.slimserver.exception.SlimConnectionException;
import org.bff.slimserver.exception.SlimException;
import org.bff.slimserver.musicobjects.favorite.SlimFavorite;
import org.bff.slimserver.musicobjects.favorite.SlimFavoriteAudioDetails;

/**
 *
 * @author bfindeisen
 */
public class FavoritesTree extends JTree implements TreeWillExpandListener, TreeExpansionListener {

    /**
     * @return the detailMap
     */
    public static HashMap<SlimFavorite, SlimFavoriteAudioDetails> getDetailMap() {
        return detailMap;
    }
    private SlimFavoritePlugin favoritePlugin;
    private SlimPlaylist playlist;
    private List<SlimFavorite> favoriteList;
    private DefaultMutableTreeNode top;
    private SplashScreen sp;
    private List<SlimFavorite> loadedList;
    private List<SlimFavorite> loadedItemList;
    private boolean showAudioItems;
    private boolean usingArt;

    private static HashMap<SlimFavorite, SlimFavoriteAudioDetails> detailMap =
            new HashMap<SlimFavorite, SlimFavoriteAudioDetails>();

    public FavoritesTree() {
        this(true);
    }

    public FavoritesTree(boolean showAudioItems) {
        super();

        setUsingArt(JukeboxProperties.getInstance().isShowCoverArt());
        
        top = new DefaultMutableTreeNode("Favorites");
        setModel(new DefaultTreeModel(top));

        setShowAudioItems(showAudioItems);

        setRowHeight(30);

        getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);

        //setShowsRootHandles(true);

        try {
            setPlaylist(JukeboxProperties.getInstance().getPlaylist());
        } catch (PlaylistException ex) {
            Logger.getLogger(FavoritesTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        try {
            setFavoritesPlugin(JukeboxProperties.getInstance().getFavoritesPlugin());
        } catch (SlimConnectionException ex) {
            Logger.getLogger(FavoritesTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        setCellRenderer(new FavoriteTreeCellRenderer());
        //addTreeExpansionListener(this);
        //listAll();
        //addMouseListener(this);
        addTreeWillExpandListener(this);
        //addTreeExpansionListener(this);

    }

    public void listAll() throws Exception {
        top = new DefaultMutableTreeNode("Favorites");

        loadedList = new ArrayList<SlimFavorite>();
        loadedItemList = new ArrayList<SlimFavorite>();
        setModel(new DefaultTreeModel(top));

        favoriteList = new ArrayList<SlimFavorite>(getFavoritesPlugin().getFavorites());

        for (SlimFavorite fav : favoriteList) {
            if (!fav.isAudio() || isShowAudioItems()) {
                DefaultMutableTreeNode category = new DefaultMutableTreeNode(fav);

                if (fav.isContainsItems()) {
                    category.add(new DefaultMutableTreeNode());
                }
                top.add(category);
            }
        }
        expandRow(0);
        //setRootVisible(false);

    }

    /**
     * @return the podcaster
     */
    public SlimFavoritePlugin getFavoritesPlugin() {
        return favoritePlugin;
    }

    /**
     * @param podcaster the podcaster to set
     */
    public void setFavoritesPlugin(SlimFavoritePlugin favoritePlugin) {
        this.favoritePlugin = favoritePlugin;
    }

    /**
     * @return the playlist
     */
    public SlimPlaylist getPlaylist() {
        return playlist;
    }

    /**
     * @param playlist the playlist to set
     */
    public void setPlaylist(SlimPlaylist playlist) {
        this.playlist = playlist;
    }

    /**
     * @return the podcastList
     */
    public List<SlimFavorite> getFavoritesList() {
        return favoriteList;
    }

    /**
     * @param podcastList the podcastList to set
     */
    public void setFavoritesList(List<SlimFavorite> favList) {
        this.favoriteList = favList;
    }

    /**
     * @return the selectedPodcast
     */
    public SlimFavorite getSelectedFavorite() {
        TreePath path = getSelectionPath();

        try {
            final DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
            if (node == null) {
                return null;
            }

            Object nodeInfo = node.getUserObject();

            if (nodeInfo instanceof SlimFavorite) {
                return (SlimFavorite) nodeInfo;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private synchronized void loadItem(DefaultMutableTreeNode node, SlimFavorite favorite) {

        node.remove(0);

        ((DefaultTreeModel) getModel()).reload(node);

        List<SlimFavorite> favorites = new ArrayList<SlimFavorite>();

        try {
            favorites.addAll(getFavoritesPlugin().getFavorites(favorite));
        } catch (SlimException ex) {
            Logger.getLogger(FavoritesTree.class.getName()).log(Level.SEVERE, null, ex);
        }

        for (SlimFavorite item : favorites) {
            if (!item.isAudio() || isShowAudioItems()) {
                DefaultMutableTreeNode itemNode = new DefaultMutableTreeNode(item);
                node.add(itemNode);
                if (item.isContainsItems()) {
                    itemNode.add(new DefaultMutableTreeNode());
                }
            }
        }
    }

    public void treeWillExpand(TreeExpansionEvent event) throws ExpandVetoException {

        TreePath path = event.getPath();

        final DefaultMutableTreeNode node = (DefaultMutableTreeNode) path.getLastPathComponent();
        if (node == null) {
            return;
        }

        Object nodeInfo = node.getUserObject();

        if (nodeInfo instanceof SlimFavorite) {

            final SlimFavorite item = (SlimFavorite) nodeInfo;


            boolean loaded = loadedList.contains(item);

            if (!loaded) {
                //node.remove(0);
                sp = new SplashScreen(Utils.getParentComponent(this), true);
                sp.setIndeterminate(true);
                sp.setTitleLabel("Loading Favorite");
                sp.setMainTextArea("\nLoading Favorite " + item.getName() + "\n\n");
                sp.setProgressBarLabel("Loading Favorite...");
                sp.pack();

                new Thread(new Runnable() {

                    public void run() {
                        loadItem(node, item);
                        sp.setStopped(true);
                        ((DefaultTreeModel) getModel()).reload(node);
                        if (node.getChildCount() == 0) {
                            setSelectionPath(getPath(node));
                        } else {
                            expandPath(getPath(node));
                        }
                    }
                }).start();
                loadedList.add(item);
            }

        }


    }

    public void treeWillCollapse(TreeExpansionEvent event) throws ExpandVetoException {
        //throw new UnsupportedOperationException("Not supported yet.");
    }

    public TreePath getPath(TreeNode node) {
        List list = new ArrayList();

        // Add all nodes to list
        while (node != null) {
            list.add(node);
            node = node.getParent();
        }
        Collections.reverse(list);

        // Convert array of nodes to TreePath
        return new TreePath(list.toArray());
    }

    public void treeExpanded(TreeExpansionEvent event) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public void treeCollapsed(TreeExpansionEvent event) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    /**
     * @return the showAudioItems
     */
    public boolean isShowAudioItems() {
        return showAudioItems;
    }

    /**
     * @param showAudioItems the showAudioItems to set
     */
    public void setShowAudioItems(boolean showAudioItems) {
        this.showAudioItems = showAudioItems;
    }

    /**
     * @return the usingArt
     */
    public boolean isUsingArt() {
        return usingArt;
    }

    /**
     * @param usingArt the usingArt to set
     */
    public void setUsingArt(boolean usingArt) {
        this.usingArt = usingArt;
    }

    private class FavoriteTreeCellRenderer extends DefaultTreeCellRenderer {

        private Icon iconRoot = new ImageIcon(getClass().getResource("/resources/slimserver/heart_25x25.png"));
        private Icon iconAudio = new ImageIcon(getClass().getResource("/resources/slimserver/musicnote_small.png"));
        private Icon iconArtist = new ImageIcon(getClass().getResource("/resources/slimserver/artists_25x25.png"));
        private Icon iconGenre = new ImageIcon(getClass().getResource("/resources/slimserver/genres_25x25.png"));
        private Icon iconYear = new ImageIcon(getClass().getResource("/resources/slimserver/years_25x25.png"));

        @Override
        public Component getTreeCellRendererComponent(JTree tree,
                Object value,
                boolean selected,
                boolean expanded,
                boolean leaf,
                int row,
                boolean hasFocus) {

            super.getTreeCellRendererComponent(
                    tree,
                    value,
                    selected,
                    expanded,
                    leaf,
                    row,
                    hasFocus);

            if (((DefaultMutableTreeNode) value).isRoot()) {
                setIcon(iconRoot);
                setText(((DefaultMutableTreeNode) value).toString());
            } else if (((DefaultMutableTreeNode) value).getUserObject() instanceof SlimFavorite) {
                SlimFavorite fav = (SlimFavorite) ((DefaultMutableTreeNode) value).getUserObject();
                setText(fav.getName());

                if(isUsingArt()) {
                switch (fav.getSlimType()) {
                    case ARTIST:
                        setIcon(iconArtist);
                        break;
                    case GENRE:
                        setIcon(iconGenre);
                        break;
                    case ALBUM:
                        SlimFavoriteAudioDetails detail = getDetailMap().get(fav);

                        if (detail == null) {
                            try {
                                detail = getFavoritesPlugin().getFavoriteAudioDetails(fav);
                                getDetailMap().put(fav, detail);
                            } catch (SlimException ex) {
                                Logger.getLogger(FavoritesTree.class.getName()).log(Level.SEVERE, null, ex);
                            }
                        }
                        setIcon(detail.getSmallIcon());

                        break;
                    case YEAR:
                        setIcon(iconYear);
                        break;
                    case OTHER:
                        if (fav.isAudio()) {
                            setIcon(iconAudio);
                        } else {
                            setIcon(getDefaultClosedIcon());
                        }
                }
                }
            }

            return this;
        }
    }
}

